/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/


#include "抛球.h"

//using namespace std;


#include <物理/物理.h>
//#include <ML/ML.h>
#include "../../A_引擎/引擎.h"


static S_结构对象指针	ddpgNet[100] = { 0 };
static uint32 输入维度 = 4+4;
static uint32 输出维度 = 4;

static std::vector<std::vector<float32>>	g环境(100);
static std::vector<std::vector<float32>>	g操作(100);
static std::vector<float32>			g奖励(100);
static std::vector<std::vector<float32>>	g环境_下一次(100);




static S_物体* g球体 = 0;
static S_物体* g方体 = 0;

static S_物理体* r球体 = 0;
static S_物理体* r方体 = 0;




static bool f_物理碰撞回调(const S_碰撞信息& info);
static void f_渲染前更新(S_Scene* scene);


void f_抛球环境初始化() {
	//f_initPython();

	for (uint32 i = 0; i < 1; ++i) {
		//ddpgNet[i] = f_createDDPG模型(输入维度, 输出维度);
	}

	for (auto& e : g环境) {
		e.resize(8);
	}
	g环境_下一次.resize(1);
	g环境_下一次[0].resize(8);



	E_物理引擎 物理引擎 = E_物理引擎::E_物理引擎_Bullet;
	S_Tranform t;
	auto* 材质 = f_创建材质(&S_框架::g_Scene->m_Physics, 0.5, 0.5, 0.5, 物理引擎);
	auto* gen球体 = f_创建球体几何体(&S_框架::g_Scene->m_Physics, 0.1, 物理引擎);
	auto* gen方体 = f_创建方体几何体(&S_框架::g_Scene->m_Physics, {0.5, 0.1, 0.5}, 物理引擎);

	r球体 = f_创建刚体(&S_框架::g_Scene->m_Physics, *gen球体, *材质, t);
	r方体 = f_创建控制物理体(&S_框架::g_Scene->m_Physics, *gen方体, *材质, t);

	r球体->f_setPos({ 0.0f, 1.0f, 0.0f });
	r球体->f_setVel({ 0.0f, 10.5f, 0.0f });
	r方体->f_setPos({ 15.0f, 0.0f, 7.0f });

	f_物理体添加到引擎(&S_框架::g_Scene->m_Physics, r球体, 0);
	f_物理体添加到引擎(&S_框架::g_Scene->m_Physics, r方体, 0);




	g球体 = f_创建球体物体(0.1, { 16, 8 }, S_框架::ctx, true);
	g球体->m_Name = L"shp";
	f_ob_set材质(g球体, S_框架::g_索引绘制材质);
	r球体->f_绑定关联对象(g球体);
	S_框架::g_Scene->m_物体.push_back(g球体);


	g方体 = f_创建BOX物体({ 1.0, 0.1, 1.0 }, S_框架::ctx, true);
	g方体->m_Name = L"box";
	g方体->f_set位置(15.0f, 0.0f, 7.0f);
	f_ob_set材质(g方体, S_框架::g_索引绘制材质);
	r方体->f_绑定关联对象(g方体);
	S_框架::g_Scene->m_物体.push_back(g方体);


	
	

	f_连接渲染前更新函数(S_框架::g_Scene, (fun_渲染前更新p)f_渲染前更新);
	S_框架::g_Scene->m_Physics.m_Bullet->m_全局碰撞回调 = f_物理碰撞回调;

}

std::vector<float32> f_抛球步进(std::vector<float32>& 动作) {

	return std::vector<float32>();
}




static uint32 世代 = 0;
static float32 误差 = 0.0;
static void f_抛球训练(const vec3& 碰撞点) {
	auto aLoc = vec3{ 15.0f, 0.0f, 7.0f };//r方体->f_getLoc();
	//auto bLoc = r球体->f_getLoc();
	auto bLoc = 碰撞点;


	g环境_下一次[0][3] = vec_normalize(&aLoc);
	g环境_下一次[0][0] = aLoc.x;
	g环境_下一次[0][1] = aLoc.y;
	g环境_下一次[0][2] = aLoc.z;

	g环境_下一次[0][7] = vec_normalize(&bLoc);
	g环境_下一次[0][4] = bLoc.x;
	g环境_下一次[0][5] = bLoc.y;
	g环境_下一次[0][6] = bLoc.z;



	auto 差 = aLoc - bLoc;
	auto len = vec_len(差);
	float32 奖励 = len;
	if (奖励 > 1.0) {
		奖励 = -1;
	}
	else {
		奖励 = 1.0 - 奖励 / 50.0;
	}
	误差 += 奖励;

	if (g操作[0].size()) {
		//f_DDPG记录训练数据(ddpgNet[0], g环境[0], g操作[0], 奖励, g环境_下一次[0]);
	}

	
	
	

	//auto a = f_预测动作(ddpgNet[0], g环境_下一次[0]);
	r球体->f_setPos({ 0.0f, 1.0f, 0.0f });
	for (uint8 i = 0; i < 3; ++i) {
		auto random = ((float)rand() / (RAND_MAX));
		float dx = 0.15 * + 0.1 * random;
		//a[i] += dx;
	}
	//vec3 力 = { a[0], a[1], a[2] };
	//力 = 力 * a[3];
	//r球体->f_施加力(力);
	//r球体->f_setVel(力);


	//g操作[0] = a;
	g环境[0] = g环境_下一次[0];


	++世代;
	if (世代 > 100) {
		std::cout << "误差 = " << 误差 << std::endl;

		世代 = 0;
		误差 = 0;
	}
}


static bool f_物理碰撞回调(const S_碰撞信息& info) {
	if (info.物体A) {
		auto& name = ((S_物体*)info.物体A)->m_Name;
		//if (name == "场景") {
			//std::cout << "物体A == " << ((S_物体*)info.物体A)->m_Name << std::endl;
		//}
		f_抛球训练(info.坐标A);
	}
	if (info.物体B) {
		auto& name = ((S_物体*)info.物体B)->m_Name;
		//if (name == "场景") {
			//std::cout << "物体B == " << ((S_物体*)info.物体B)->m_Name << std::endl;
		//}
	}

	//if (info.速度A > info.速度B) {
	if (info.物体A) {
		//g奖励[((S_物体*)info.物体A)->m_ID] -= info.冲量 * 10;
	}
	//}
	//else {
	if (info.物体B) {
		//g奖励[((S_物体*)info.物体B)->m_ID] -= info.冲量 * 10;
	}
	//}


	
	

	//std::cout << "冲量 b == " << info.冲量 << std::endl;
	return false;
	
}


static void f_渲染前更新(S_Scene* scene) {
	

}



